//
//  LYPickerComponent.m
//  PickerDemo
//
//  Created by 李阳 on 2018/4/17.
//  Copyright © 2018年 李阳. All rights reserved.
//

#import "LYPickerView.h"

#define SCREEN_WIDTH   [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT  [UIScreen mainScreen].bounds.size.height

#define SCALE_6  (SCREEN_WIDTH/375.0f)

#define kDefaultFont [UIFont fontWithName:@"PingFangSC-Regular" size:25]
#define kDefaultRowHeight 50*SCALE_6

static NSInteger const kUninitialize = -1;

@interface LYColumnItem ()
/// 列号
@property (nonatomic, assign) NSInteger columnIndex;
@end
@implementation LYColumnItem
@end

#pragma mark -
@interface LYColumnStyle ()
@end
@implementation LYColumnStyle
- (instancetype)init
{
    self = [super init];
    if (!self) return nil;
    _textAlignment = NSTextAlignmentCenter;
    _font = kDefaultFont;
    return self;
}
@end


#pragma mark -
@interface LYPickerView () <UIPickerViewDelegate, UIPickerViewDataSource>
@end

@implementation LYPickerView

#pragma mark Public

- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated needCallback:(BOOL)needed
{
    [self selectRow:row inComponent:component animated:animated];
    
    if (needed)
    {
        if ([self.delegate respondsToSelector:@selector(pickerView:didSelectRow:inComponent:)])
        {
            [self.delegate pickerView:self didSelectRow:row inComponent:component];
        }
    }
}

#pragma mark UIPickerViewDelegate
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
    CGFloat width = pickerView.frame.size.width;
    CGFloat defaultW =  width / self.numberOfComponentsTotal;
    
    if (component < self.styles.count)
    {
        LYColumnStyle *style = self.styles[component];
        if (style &&
            component == style.columnIndex &&
            (style.widthRatio > 0))
        {
            return style.widthRatio * width;
        }
    }
    
    return [self widthForComponent:component] ?: defaultW;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    CGFloat defaultH = kDefaultRowHeight;
    if (component < self.styles.count)
    {
        LYColumnStyle *style = self.styles[component];
        if (style &&
            component == style.columnIndex &&
            style.rowHeight)
        {
            return style.rowHeight;
        }
    }
    if (self.rowHeight)
    {
        return self.rowHeight;
    }
    return [self rowHeightForComponent:component] ?: defaultH;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return [self titleForRow:row forComponent:component];
}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view
{
    for (UIView *subView in pickerView.subviews)
    {
        if (subView.frame.size.height < 1)
        {
            subView.backgroundColor = self.seperatorColor;
        }
    }
    
    if (self.selectedBackgroundColor)
    {
        UIView *bgView = [self _selectedBackgroundViewForPickerView:pickerView atColumn:0];
        bgView.backgroundColor = self.selectedBackgroundColor;
    }
    
    NSInteger columAli = -1;
    UIFont *font;
    UIColor *selectedTextColor;
    if (component < self.styles.count)
    {
        LYColumnStyle *style = self.styles[component];
        if (style && component == style.columnIndex)
        {
            columAli = style.textAlignment;
            font = style.font;
            selectedTextColor = style.selectedTextColor;
        }
    }
    
    UILabel *label = (UILabel *)view;
    if (!label)
    {
        label = [[UILabel alloc]init];
        label.adjustsFontSizeToFitWidth = YES;
        label.textAlignment = (columAli != -1 && columAli != _textAlignment) ? columAli : _textAlignment;
        label.font = font ?: self.font;
        [label setBackgroundColor:[UIColor clearColor]];
        label.textColor = selectedTextColor ?: self.selectedTextColor;
    }
    
    NSString *title = [self titleForRow:row forComponent:component];
    
    label.text = title;
    UIView *customView = [self viewForRow:row forComponent:component reusingLabel:label title:title];
    
    return customView ?: label;
}
- (UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingLabel:(UILabel *)label title:(NSString *)title
{
    return nil;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    [self didSelectRow:row inComponent:component];
}


#pragma mark UIPickerViewDataSource
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return [self numberOfComponentsTotal];
}

// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    return [self numberOfRowsInComponent:component];
}


- (CGFloat)widthForComponent:(NSInteger)component { return 0.0; }
- (CGFloat)rowHeightForComponent:(NSInteger)component { return 0.0; }
- (NSString *)titleForRow:(NSInteger)row forComponent:(NSInteger)component { return nil; }
- (void)didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{ }
- (NSInteger)numberOfComponentsTotal { return 0; }
- (NSInteger)numberOfRowsInComponent:(NSInteger)component { return 0; }


#pragma mark Publick

- (void)setStyles:(NSArray<LYColumnStyle *> *)styles
{
    _styles = styles;
    [styles enumerateObjectsUsingBlock:^(LYColumnStyle * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
    {
        obj.columnIndex = idx;
    }];
}


- (UIView *)_selectedBackgroundViewForPickerView:(UIPickerView *)pickerView atColumn:(NSInteger)column
{
    NSArray *subviews = pickerView.subviews;
    if (subviews.count > 0)
    {
        UIView *coloms = subviews.firstObject;
        if (coloms)
        {
            [coloms setValue:[UIColor grayColor] forKeyPath:@"interactionTintColor"];
            NSArray *subviewCache = [coloms valueForKey:@"subviewCache"];
            if (subviewCache.count > 0)
            {
                return [subviewCache[column] valueForKey:@"middleContainerView"];
            }
        }
    }
    return nil;
}

#pragma mark LiftCycle
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) return nil;
    [self setup];
    return self;
}

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self setup];
}

/// 初始化
- (void)setup
{
    self.delegate = self;
    self.dataSource = self;
    
    _textAlignment = NSTextAlignmentCenter;
    _font = kDefaultFont;
    self.seperatorColor = [UIColor colorWithRed:238 / 255.0 green:236.0 / 255.0 blue:233 / 255.0 alpha:1.0];;
    
    self.selectedTextColor = [UIColor colorWithRed:81 / 255.0 green:152 / 255.0 blue:193 / 255.0 alpha:1.0];;
    self.rowHeight = kDefaultRowHeight;
}


@end

#pragma mark -

@implementation LYColumnData

- (instancetype)init
{
    self = [super init];
    if (!self) return nil;
    _selectedIndex = kUninitialize;
    _lastSelectedIndex = kUninitialize;
    return self;
}

- (NSInteger)targetIndex
{
    if (_selectedIndex != -1)
    {
        return _selectedIndex;
    }
    if (!_selectedValue)
    {
        _selectedValue = self.datas[0];
        return 0;
    }
    
    NSUInteger index = [self.datas indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL * _Nonnull stop)
    {
        NSParameterAssert(![obj isKindOfClass:[self.selectedValue class]]);
        
        if ([obj isKindOfClass:[NSString class]]) {
            return [obj isEqualToString:self.selectedValue];
        } else
        {
            NSParameterAssert(self.transformBlock);
            NSString *objString = self.transformBlock(obj);
            NSString *selectedString = self.transformBlock(self.selectedValue);
            return [objString isEqualToString:selectedString];
        }
    }];
    return index == NSNotFound ? 0 : index;
}

- (void)selectRow:(NSInteger)row
{
    if (!_datas.count || row > _datas.count - 1)
    {
        return;
    }
    if (_lastSelectedIndex == kUninitialize)
    {
        _lastSelectedIndex = row;
    } else
    {
        _lastSelectedIndex = _selectedIndex;
    }
    _selectedIndex = row;
    
    NSString *rowValue = _datas[row];
    if (_lastSelectedValue == nil)
    {
        _lastSelectedValue = rowValue;
    } else
    {
        _lastSelectedValue = _selectedValue;
    }
    _selectedValue = rowValue;
}

- (NSString *)titleForRow:(NSInteger)row
{
    if (!_datas.count || row > _datas.count - 1)
    {
        return nil;
    }
    id obj = self.datas[row];
    if ([obj isKindOfClass:[NSString class]])
    {
        return (NSString *)obj;
    }
    NSParameterAssert(self.transformBlock);
    return self.transformBlock(obj);
}

- (void)dealloc
{
    _transformBlock = nil;
}
@end


#pragma mark -
@interface LYStaticPicker ()
/// 选中的值改变的block
@property (nonatomic, copy) void(^selectedValueDidChangeBlock)(__kindof LYPickerView *view);
@end
@implementation LYStaticPicker


#pragma mark Overide
- (NSInteger)numberOfComponentsTotal
{
    return self.datas.count;
}
- (NSInteger)numberOfRowsInComponent:(NSInteger)component
{
    return self.datas[component].datas.count;
}
- (NSString *)titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    LYColumnData *data = self.datas[component];
    return [data titleForRow:row];
}
- (void)didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    NSInteger count = self.datas.count;
    if (!count || component > count - 1)
    {
        return;
    }
    LYColumnData *data = self.datas[component];
    [data selectRow:row];
    [self didSelectRowForColumnData:data];
    
    !_selectedValueDidChangeBlock ?: _selectedValueDidChangeBlock(self);
}
- (void)didSelectRowForColumnData:(LYColumnData *)data {}


#pragma mark Public
- (void)setDatas:(NSArray<LYColumnData *> *)datas
{
    [self setDatas:datas animated:NO];
}

- (void)setDatas:(NSArray<LYColumnData *> *)datas animated:(BOOL)animated
{
    _datas = datas;
    
    [datas enumerateObjectsUsingBlock:^(LYColumnData *data, NSUInteger idx, BOOL *stop)
    {
        data.columnIndex = idx;
        NSInteger row = data.targetIndex;
        [self selectRow:row inComponent:idx animated:animated];
        [data selectRow:row];
    }];
}

- (BOOL)selectValue:(NSString *)value inComponent:(NSInteger)component animated:(BOOL)animated
{
    if (component > self.datas.count - 1) return NO;
    LYColumnData *data = self.datas[component];
    NSInteger row = [data.datas indexOfObject:value];
    if (row == NSNotFound) return NO;
    [self selectRow:row inComponent:component animated:animated];
    [data selectRow:row];
    return YES;
}

- (BOOL)selectValue:(NSString *)value inComponent:(NSInteger)component animated:(BOOL)animated needCallback:(BOOL)needed
{
    if (component > self.datas.count - 1) return NO;
    LYColumnData *data = self.datas[component];
    NSInteger row = [data.datas indexOfObject:value];
    if (row == NSNotFound) return NO;
    [self selectRow:row inComponent:component animated:animated needCallback:needed];
    [data selectRow:row];
    return YES;
}

- (NSUInteger)rowInComponent:(NSInteger)component
                 passingTest:(BOOL(^)(id value, NSString *title, NSUInteger idx))block
{
    if (!block) return NSNotFound;
    if (component > self.datas.count - 1) return NSNotFound;
    LYColumnData *data = self.datas[component];
    NSInteger row = [data.datas indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL * _Nonnull stop)
    {
        BOOL result = NO;
        if ([obj isKindOfClass:[NSString class]])
        {
            result = block(obj, obj, idx);
        } else
        {
            NSParameterAssert(data.transformBlock);
            NSString *objStr = data.transformBlock(obj);
            result = block(obj, objStr, idx);
        }
        
        if (result)
        {
            *stop = YES;
        }
        return result;
    }];
    return row;
}

- (void)setColumsSelectedValueDidChangeBlock:(void (^)(__kindof LYPickerView *))block
{
    _selectedValueDidChangeBlock = block;
}

- (void)dealloc
{
    _selectedValueDidChangeBlock = nil;
}
@end


